package org.mybatis.generator.codegen.spring.jdbc.repository.elements;

import static org.mybatis.generator.internal.util.JavaBeansUtil.getGetterMethodName;

import java.util.List;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.codegen.spring.jdbc.repository.AbstractRepGenerator;

public class UpdateByPrimaryKeySelectiveMethodGenerator extends AbstractRepGenerator {

	@Override
	public void addImplementationElements(TopLevelClass topLevelClass) {
	//	String domainObjectName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();
//		FullyQualifiedJavaType returnType = new FullyQualifiedJavaType(domainObjectName);
//		FullyQualifiedJavaType parameterType = new FullyQualifiedJavaType(domainObjectName);
		FullyQualifiedJavaType parameterType = introspectedTable.getRules().calculateAllFieldsClass();
		FullyQualifiedJavaType returnType = introspectedTable.getRules().calculateAllFieldsClass();
//		method.setReturnType(returnType);
		topLevelClass.addImportedType(returnType);
		topLevelClass.addImportedType(parameterType);
		// 添加依赖类
		addImportedType(topLevelClass);
		
		// 获得主键信息
		List<IntrospectedColumn> pks = introspectedTable.getPrimaryKeyColumns();

		// 设置方法
		Method method = new Method();
		
		method.setVisibility(JavaVisibility.PUBLIC);
		method.setReturnType(returnType);
		method.setName("updateByPrimaryKeySelective");
		method.addParameter(new Parameter(parameterType, "entity"));
		method.addException(new FullyQualifiedJavaType(
				"org.springframework.dao.DataAccessException"));
		// 方法内部代码
		/*
		this.jdbcTemplate.update(
	                "UPDATE pets SET name=:name, birth_date=:birth_date, type_id=:type_id, " +
	                    "owner_id=:owner_id WHERE id=:id",
	                    new MapSqlParameterSource()
	                    .addValue("id", entity.getId())
	                    .addValue("name", entity.getName())
	                    .addValue("birth_date", entity.getBirthDate().toDate())
	                    .addValue("type_id", entity.getType().getId())
	                    .addValue("owner_id", entity.getOwner().getId()));
		return entity;*/
		StringBuilder sb = new StringBuilder();
		method.addBodyLine("StringBuilder sql = new StringBuilder(\"UPDATE \");");
		sb.setLength(0);
		sb.append("sql.append(\"");
		sb.append(introspectedTable.getFullyQualifiedTable().getIntrospectedTableName());
		sb.append(" SET \");");
		method.addBodyLine(sb.toString());
		List<IntrospectedColumn> iterable = introspectedTable.getNonPrimaryKeyColumns();
		for (int i = 0, size = iterable.size(); i < size; i++) {
			IntrospectedColumn element = iterable.get(i);
			sb.setLength(0);
			sb.append("if(entity.");
			sb.append(getGetterMethodName(element.getJavaProperty(),element.getFullyQualifiedJavaType()));
			sb.append("()!= null ){");
			method.addBodyLine(sb.toString());
			sb.setLength(0);
			sb.append("sql.append(\"");
			sb.append(element.getActualColumnName());
			sb.append(" =:");
			sb.append(element.getActualColumnName());
			sb.append("\");");
			method.addBodyLine(sb.toString());
				sb.setLength(0);
				sb.append("sql.append(\",\");");
				method.addBodyLine(sb.toString());
			
			method.addBodyLine("}");
		}
		
		method.addBodyLine("String updateSql = sql.substring(0, sql.lastIndexOf(\",\"));");
		sb.setLength(0);
		sb.append("sql.setLength(0);");
		method.addBodyLine(sb.toString());
		method.addBodyLine("sql.append(updateSql);");
		sb.setLength(0);
		sb.append("sql.append(\" WHERE ");
		for (int i = 0; i < pks.size(); i++) {
			IntrospectedColumn introspectedColumn = pks.get(i);
			if (i != 0) {
				sb.append(" and ");
			}
			String column = toCaseName(introspectedColumn.getActualColumnName());
			sb.append(column);
			sb.append(" = :");
			sb.append(column);
		}
		sb.append("\");");
		method.addBodyLine(sb.toString());
		
		method.addBodyLine("MapSqlParameterSource mapSqlParameterSource = new MapSqlParameterSource();");
		
		for (int i = 0, size = iterable.size(); i < size; i++) {
			IntrospectedColumn element = iterable.get(i);
			
			sb.setLength(0);
			sb.append("if(entity.");
			sb.append(getGetterMethodName(element.getJavaProperty(),element.getFullyQualifiedJavaType()));
			sb.append("()!= null ){");
			method.addBodyLine(sb.toString());
			sb.setLength(0);
			sb.append("mapSqlParameterSource.addValue(\"");
			sb.append(element.getActualColumnName());//.addValue("id", entity.getId())
			sb.append("\" ,entity.");
			sb.append(getGetterMethodName(element.getJavaProperty(),element.getFullyQualifiedJavaType()));
			sb.append("());");
			method.addBodyLine(sb.toString());
			method.addBodyLine("}");
		}
		
		method.addBodyLine("this.jdbcTemplate.update(sql.toString(), mapSqlParameterSource);");
		sb.setLength(0);
		sb.append("entity = findOneById(");
		for (int i = 0; i < pks.size(); i++) {
			IntrospectedColumn introspectedColumn = pks.get(i);
			if (i != 0) {
				sb.append(" , ");
			}
			sb.append("entity.");
			sb.append(getGetterMethodName(introspectedColumn.getJavaProperty(), introspectedColumn.getFullyQualifiedJavaType()));
			sb.append("()");
		}
		sb.append(");");
		method.addBodyLine(sb.toString());
		method.addBodyLine("return entity;");

		context.getCommentGenerator().addGeneralMethodComment(method, introspectedTable);

		if (context.getPlugins().clientInsertMethodGenerated(method, topLevelClass,
				introspectedTable)) {
			topLevelClass.addMethod(method);
		}

	}

	/**
	 * @param topLevelClass
	 */
	private void addImportedType(TopLevelClass topLevelClass) {
		topLevelClass.addImportedType(new FullyQualifiedJavaType("java.util.Map"));
		topLevelClass.addImportedType(new FullyQualifiedJavaType("java.util.HashMap"));
		topLevelClass.addImportedType(new FullyQualifiedJavaType(
				"org.springframework.dao.EmptyResultDataAccessException"));
		topLevelClass.addImportedType(new FullyQualifiedJavaType(
				"org.springframework.jdbc.core.BeanPropertyRowMapper"));
		topLevelClass.addImportedType(new FullyQualifiedJavaType(
				"org.springframework.dao.DataAccessException"));
		topLevelClass.addImportedType(new FullyQualifiedJavaType(
				"org.springframework.jdbc.core.namedparam.MapSqlParameterSource"));
		FullyQualifiedJavaType modelClass = new FullyQualifiedJavaType(
				introspectedTable.getBaseRecordType());
		topLevelClass.addImportedType(modelClass);
	}

}
